package me.itsoo.artemis.framework.core.eventbus;

import me.itsoo.artemis.framework.core.util.AnnotationUtils;
import me.itsoo.artemis.framework.core.util.Assert;
import me.itsoo.artemis.framework.core.util.ReflectUtils;
import me.itsoo.artemis.framework.core.util.StringUtils;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * EventBus
 *
 * @author zxy
 * @version 0.0.1
 * @since 2023/6/14
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class EventBus {

    private final Map<String, Set<Subscriber>> registryTable = new ConcurrentHashMap<>();

    /**
     * 创建 EventBus
     *
     * @return EventBus
     */
    public static EventBus create() {
        return new EventBus();
    }

    /**
     * 注册订阅
     *
     * @param subClass Class
     * @return boolean
     */
    public boolean register(Class<? extends Subscriber> subClass) {
        if (subClass != null) {
            final SubscriberTopic ann = AnnotationUtils.findAnnotation(subClass, SubscriberTopic.class);
            Assert.notNull(ann, "'subClass' must be with @SubscriberTopic");
            final String topic = StringUtils.defaultIfBlank(ann.value(), subClass.getSimpleName());
            return register(topic, subClass);
        }

        return false;
    }

    /**
     * 注册订阅
     *
     * @param topic    String
     * @param subClass Class
     * @return boolean
     */
    public boolean register(String topic, Class<? extends Subscriber> subClass) {
        if (subClass != null) {
            final Set<Subscriber> set = registryTable.computeIfAbsent(topic, k -> new LinkedHashSet<>());
            final Subscriber sub = ReflectUtils.newInstance(subClass);
            return (sub != null) && set.add(sub);
        }

        return false;
    }

    /**
     * 注册订阅
     *
     * @param subClasses Collection
     */
    public void registerAll(Collection<Class<? extends Subscriber>> subClasses) {
        if (subClasses != null) {
            for (Class<? extends Subscriber> subClass : subClasses) {
                register(subClass);
            }
        }
    }

    /**
     * 注册订阅
     *
     * @param topic      String
     * @param subClasses Collection
     */
    public void registerAll(String topic, Collection<Class<? extends Subscriber>> subClasses) {
        if (subClasses != null) {
            for (Class<? extends Subscriber> subClass : subClasses) {
                register(topic, subClass);
            }
        }
    }

    /**
     * 发布订阅事件
     *
     * @param topic String
     * @param event Event
     */
    public void publishEvent(String topic, Event event) {
        if (event != null) {
            final Set<Subscriber> set = registryTable.get(topic);
            Assert.notNull(set, "Not found topic '" + topic + "', please register first");
            for (Subscriber subscriber : set) {
                subscriber.listen(event);
            }
        }
    }
}
